package com.luomo.java.juc.volatiledemo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * volatile特性
 * 1.保证可见性
 * 2.不保证原子性
 * 3.禁止指令重排
 *
 * @author LiuMei
 * @date 2021-01-12.
 */
public class VolatileDemo {

    public static void main(String[] args) {
        seeOkByVolatile();
    }

    /**
     * volatile不保证原子性
     * <p>
     * 如何解决：
     * 1.加sync（太重）
     * 2.使用JUC下的原子类
     */
    private static void atomicityNo() {
        MyData myData = new MyData();
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    myData.add();
                    myData.addAtomic();
                }
            }, "线程" + i + 1).start();
        }
        //等待线程计算结束,获取最终结果
        //后台默认两个线程main和GC线程
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + "\tfinal int number value：" + myData.number);
        System.out.println(Thread.currentThread().getName() + "\tfinal atomicInteger number value：" + myData.atomicInteger);
    }

    /**
     * volatile可以保证可见性，及时通知其他线程，主物理内存的值已被修改
     * <p>
     * int number = 0; 加不加volatile修饰，导致不同结果
     */
    private static void seeOkByVolatile() {
        MyData myData = new MyData();
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t come in");
            try {
                TimeUnit.SECONDS.sleep(3);
                myData.addTo60();
                System.out.println(Thread.currentThread().getName() + "\t updated number value:" + myData.number);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();

        while (myData.number == 0) {
            //main一直循环,直到number不等于0
        }
        System.out.println(Thread.currentThread().getName() + "\t mission is over");
    }

}

class MyData {
        volatile
    int number = 0;


    public void addTo60() {
        this.number = 60;
    }

    /**
     * number 添加了volatile关键字修饰，不保证原子性
     */
    public void add() {
        number++;
    }

    AtomicInteger atomicInteger = new AtomicInteger();

    public void addAtomic() {
        atomicInteger.getAndIncrement();
    }
}
